home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
UTILITIE
/
CPU_MEMO
/
0978.ZIP
/
FILES33.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-07-03
|
16KB
|
329 lines
;****************************************************************************
; file: files33.asm by: Steven M. Gibson, Irvine, CA created: 06/06/87
;****************************************************************************
;
; * * * PUBLIC DOMAIN COPYRIGHT RELEASE NOTICE * * *
;
; THIS PROGRAM, IN BOTH SOURCE CODE AND OBJECT FORM, HAS BEEN EXPLICITLY
; PLACED INTO THE PUBLIC DOMAIN BY ITS SOLE AUTHOR AND OWNER, STEVEN GIBSON,
; OF IRVINE, CA. IT MAY THEREFORE BE FREELY REPRODUCED, EXCHANGED, UPLOADED
; AND DOWNLOADED. HOWEVER THE AUTHOR REQUESTS THAT THIS NOTICE OF RELEASE
; AND ORIGIN OF AUTHORSHIP BE LEFT INTACT AND THAT THIS PROGRAM OR ITS DIRECT
; DERRIVATIVES, IF ANY, *NOT* BE SOLD FOR PROFIT. ALSO, PLEASE KEEP THE
; ENTIRE SET OF FILES TOGETHER AS ONE PACKAGE. ----> Thanks
;
;****************************************************************************
;
; About The Program: FILES.COM (source code file: files33.asm)
;
; "FILES.COM" is a small resident (TSR) program which overcomes a major
; glitch in the way IBM has implemented DOS 3.30. Specifically, it handles
; the requirements of explicitly ASKING DOS for additional handles and
; keeping a block of RAM available for DOS when this request is made.
; Any program can now have up to 256 files open when under 3.3 (counting
; the standard pre-opened default files) if the command "FILES" is issued
; first. This program also has the interesting ability to spontaneously
; remove itself ("Un-TSR") from memory after doing its job.
;
; If you wish to suppress the message FILES delivers when it is run, simply
; put anything after the command, (like: "files shhh") and it won't say a
; word as it goes resident. Otherwise it makes a short (non-commercial)
; statement of its intent as it terminates.
;
; NOTE: This program *ONLY* makes sense when under version 3.3 of DOS, and
; it will refuse to run under any earlier DOS versions. Use the
; other DOS 3.x version of FILES.COM (source file: files3x.asm)
;****************************************************************************
;
; About These SOURCE CODE FILES:
;
; This source code file, and the companion OPENER.ASM source code file, were
; written to be instructional, clear, and a bit tutorial in nature. As such
; they have been commented more heavily than normal self-communication
; would normally dictate. I hope you will find them interesting, useful,
; and not overly verbose. They are also examples of a general coding style
; I've found to endure quite well. Adopt it if you like it.
;
; NOTE: These files were created using the incredible file editor: BRIEF
;
;****************************************************************************
;
; To make a COM file from this ASM source code:
;
; masm files33, files33; <--- assemble the .asm to .obj
; link files33; <--- link the .obj to .exe
; exe2bin files33 files33.com <--- convert .exe to .com
; del files33.obj <--- delete the intermediate debris
; del files33.exe
;
;****************************************************************************
;----------------------------------------------------------------------------
; E Q U A T E S
;----------------------------------------------------------------------------
CR equ 0Dh ; ASCII
LF equ 0Ah
COM_TERMINATE equ 20h ; .COM program termination
DOS_FUNC equ 21h ; Interrupt to call DOS
DOS_PRINTSTRING equ 09h ; Dos Sub-Function Defs
DOS_SET_VECTOR equ 25h
DOS_VERSION_NUMBER equ 30h ; " "
DOS_STAY_RESIDENT equ 31h
DOS_GET_VECTOR equ 35h
DOS_CREATE equ 3Ch ; " "
DOS_OPEN equ 3DH
DOS_ALLOC equ 48H
DOS_DEALLOC equ 49H ; " "
DOS_SETBLOCK equ 4AH
SET_HANDLE_COUNT equ 67h ; <----- The *NEW* function!
NEW_HANDLE_COUNT equ 256 + 1 ; so we cam have 256 files
NEW_MAX_HANDLES equ 256 ; assuming 256 handle params
MINIMUM_VERSION equ 3 * 256 + 30 ; version "3"."30"
;----------------------------------------------------------------------------
; C O D E S E G M E N T
;----------------------------------------------------------------------------
CODESEG SEGMENT BYTE PUBLIC
ASSUME CS:CODESEG, DS:CODESEG
ORG 02Ch ; pointer to this program's environ
Environment LABEL WORD
ORG 080h
ParameterCount LABEL BYTE ; count of the command-line params
ORG 100h ; .com programs execute from 0100h
ComStart: jmp TransientCode ; jump over our resident portion
;****************************************************************************
; RESIDENT CODE PORTION BEGINS HERE
;****************************************************************************
OldDosInt dd ? ; original int 21 vector pointer
HoleSegment dw ? ; segment location of the "hole"
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
; NOTE TO THE READER: The following "resident portion" of the TSR will make
; *MUCH* more sense if you have FIRST read the "transient portion" below. I
; suggest that you jump ahead and read that first, then come back to here....
;----------------------------------------------------------------------------
Int21Intercept:
;----------------------------------------------------------------------------
; The transient portion of this program pointed DOS' calling Interrupt 21
; here before terminating itself. Therefore we receive control every time
; anyone does an Int21h call to DOS. (Until we've fulfilled our mission)
;----------------------------------------------------------------------------
cmp ah, DOS_OPEN ; was the call an open handle?
je MakeRoom ; yep, see if we're alive
cmp ah, DOS_CREATE ; was it a create handle?
jne Int21Continue ; nope, so just pass it on
MakeRoom: cmp cs:HoleSegment, 0 ; did we already do our thing?
je Int21Continue ; yep, so don't do it again!
push ax ; save the caller's calling
push bx ; parameters on "his" stack
push es
;----------------------------------------------------------------------------
; Free up the memory block, located at "HoleSegment", which was previously
; allocated by the transient portion of this program.
;----------------------------------------------------------------------------
mov es, cs:HoleSegment ; get the segment number
mov cs:HoleSegment, 0 ; zero it so we don't again
mov ah, DOS_DEALLOC
int DOS_FUNC ; and release that ram block
;----------------------------------------------------------------------------
; Now use DOS 3.3's new function: "Set Handle Count" to get DOS to use the
; RAM memory we've just now freed up for the purpose of allowing the handles
;----------------------------------------------------------------------------
mov ah, SET_HANDLE_COUNT ; ask DOS for mucho handles
mov bx, NEW_HANDLE_COUNT ; using the new 3.3 function
int DOS_FUNC
;----------------------------------------------------------------------------
; Now we verrify that interrupt 21 is still pointing at us, and if so
; we're able to re-point it to where it was originally pointing, (thus
; un-vectoring ourselves) then release even ourselves from ram too!
;----------------------------------------------------------------------------
mov ah, DOS_GET_VECTOR
mov al, DOS_FUNC ; get int 21's address
int DOS_FUNC
cmp bx, OFFSET Int21Intercept
jne RestoreStack ; it moved, so we must remain
mov ax, es ;
mov bx, cs ; can't compare segment regs,
cmp ax, bx ; <sigh> so we do it this way
jne RestoreStack
;----------------------------------------------------------------------------
; DOS' calling Interrupt 21 is still pointing at us, (as it should always be
; unless some later resident program or the currently executing program has
; changed it), so we're free to point it back to where it was pointing.
;----------------------------------------------------------------------------
push dx ; we need ds and dx so we
push ds ; stack them too for a moment
mov dx, WORD PTR cs:OldDosInt
mov ds, WORD PTR cs:OldDosInt+2
mov ah, DOS_SET_VECTOR
mov al, DOS_FUNC
int DOS_FUNC
pop ds ; and restore caller's ds:dx
pop dx
;----------------------------------------------------------------------------
; Now, since we're no longer in the Interrupt 21 calling chain, we're free
; to leave ram too, so now we can release our own code segment as well!
; Since the transient portion already freed our environment allocation, and
; we just unhooked ourselves from Int21, this final release of our code seg
; will create a contiguous free region underneath the currently running
; application program which DOS will collect together and recover as soon
; as the program running now terminates. This means that we will have
; completely and spontaneously removed ourselves from RAM.
;----------------------------------------------------------------------------
mov ax, cs ; get our own code segment
mov es, ax
mov ah, DOS_DEALLOC
int DOS_FUNC ; and release our ram block
;----------------------------------------------------------------------------
; Now we restore the caller's original parameters (remember, we got control
; because he was doing a DOS call himself) and pass control on to DOS so
; that the caller's original job can be performed as if we were never here.
;----------------------------------------------------------------------------
RestoreStack: pop es ; now restore our working
pop bx ; registers
pop ax
Int21Continue: jmp cs:[OldDosInt] ; and "jump" to DOS so that
; and caller's return is
; left at the top of the stack
;****************************************************************************
; END OF THE RESIDENT CODE
;****************************************************************************
;----------------------------------------------------------------------------
;****************************************************************************
; BEGINNING OF THE TRANSIENT (NON-RESIDENT) CODE
;****************************************************************************
;----------------------------------------------------------------------------
; This program makes NO sense under any versions of DOS prior to 3.3, so we
; refuse to operate at all if we're using a prior DOS.
;----------------------------------------------------------------------------
TransientCode: mov ah, DOS_VERSION_NUMBER ; first we need to make sure
int DOS_FUNC ; this guy has DOS 3.3!
xchg ah, al ; make the number linear
cmp ax, MINIMUM_VERSION
jae MakeUsResident ; yep, DOS ver 3.3 or later!
mov dx, OFFSET WrongDosMsg ; nope, he's using a version
mov ah, DOS_PRINTSTRING ; of DOS prior to 3.3
int DOS_FUNC
int COM_TERMINATE ; we're not "supposed" to quit
; this way anymore, but it's
; so easy!
MakeUsResident:
;----------------------------------------------------------------------------
; When DOS loads a program it is allocated ALL of the remaining contiguous
; memory from its load-point to the end of ram, so we start by modifying
; this allocation so that it just encompasses our own program's code...
;----------------------------------------------------------------------------
mov bx, OFFSET EndOfTransient + 15 ; get our ending offset
mov cl, 4 ; and compute the number of
shr bx, cl ; segments (the 15 rounds up)
mov ah, DOS_SETBLOCK ; now shrink our memory block
int DOS_FUNC
;----------------------------------------------------------------------------
; Every program also receives a set of strings in its Environment Block.
; Since we don't need this, it's polite to release it too. (Actually it's
; necessary if we, being a TSR, are ever to completely evacuate RAM.)
; (Dos manages memory allocation on a segment-by-segment, paragraph-by-
; paragraph basis. So we always refer to allocated blocks of memory by
; referencing that block's segment number. In the case of our Environment
; segment, our own PSP (program segment prefix) has a pointer to that seg.)
;----------------------------------------------------------------------------
mov es, Environment ; get our environment's seg
mov ah, DOS_DEALLOC
int DOS_FUNC ; and release it too!
;----------------------------------------------------------------------------
; Now we grab up a block of memory large enough to allow DOS to open 256
; files. Our resident half will free this up when the time is right!
;----------------------------------------------------------------------------
mov bx, (NEW_MAX_HANDLES+15)/16 ; use paragraphs
mov ah, DOS_ALLOC
int DOS_FUNC
mov HoleSegment, ax ; and save the block's segment
; for our resident half
;----------------------------------------------------------------------------
; Now, since our whole methodology involves having the resident portion
; FREE UP this newly allocated ram block, then ask DOS for a lot of handles
; WHEN the next-to-run program asks DOS to open or create a file for it, we
; need to intercept all subsequent DOS calls until we're done with our job.
; So we re-route Interrupt 21 through our resident half.
;----------------------------------------------------------------------------
mov ah, DOS_GET_VECTOR ; get the current
mov al, DOS_FUNC ; interrupt 21 value
int DOS_FUNC
mov WORD PTR OldDosInt , bx ; saving it in the
mov WORD PTR OldDosInt+2, es ; resident portion
mov dx, OFFSET Int21Intercept ; that done, we set
mov ah, DOS_SET_VECTOR ; int 21 to point
mov al, DOS_FUNC ; to our resident
int DOS_FUNC ; module
;----------------------------------------------------------------------------
; Nearly done, and just to be quite clear, we say something appropriate to
; our operator before we terminate ... but *ONLY* if he didn't specifically
; ask as to remain silent. The byte at location 80h in our PSP contains
; the count of parameters on our invoking command line. If this is not
; zero, we're suppose to suppress all departing exclamation....
;----------------------------------------------------------------------------
cmp ParameterCount, 0 ; is it zero?
jne NowWeTSR ; nope, so be quiet!
mov dx, OFFSET FilesMessage ; yep, so we get to
mov ah, DOS_PRINTSTRING ; say goodbye now
int DOS_FUNC
;----------------------------------------------------------------------------
; Finally we tell DOS that we're all through, asking it nicely to terminate
; us but leave the first half of us resident. That top half will be awakened
; every time DOS is called until it's done its job. "TransientCode" is the
; beginning of our second half, and the "+15" does the right thing with
; rounding as we convert into our paragraph size.
;----------------------------------------------------------------------------
NowWeTSR: mov ah, DOS_STAY_RESIDENT ; compute the number
mov dx, OFFSET TransientCode + 15 ; of paragraphs to
mov cl, 4 ; keep resident
shr dx, cl
int DOS_FUNC ; this "call", being "TSR" never gets
; control returned by DOS
;----------------------------------------------------------------------------
; T E X T M E S S A G E S
;----------------------------------------------------------------------------
WrongDosMsg db CR,LF, "This program only applies to DOS versions "
db "3.3 and (presumably) later. Sorry!",CR,LF,"$"
FilesMessage db CR,LF
db "The next program to run may open up to "
db 22h,"FILES=",22h," files." ; asc(")=22h
db CR,LF,"$"
;----------------------------------------------------------------------------
EndOfTransient = THIS BYTE ; the address of this label is used
; to compute our load-module size
CODESEG ENDS
END ComStart ; and that's all there is to it!